// $Id: application.h 527 2008-06-02 00:14:11Z agjermun $
//
// ml278
// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifndef __APPLICATION_H_
#define __APPLICATION_H_
#include "Ogre.h"
#include "OgreStringConverter.h"
#include "OgreException.h"
#include "OgreConfigFile.h"

#ifdef WIN32
#include <WIN32/OgreTimerImp.h>
#else
#include <GLX/OgreTimerImp.h>
#endif

#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include "baseworldobject.h"
#include "colshapemanager.h"
#include "loadingbar.h"
#include "eventmanager.h"
#include "eventlistener.h"
#include "extendedcamera.h"
#include "spaceship.h"
#include "keybindingsmanager.h"
#include "QuickGUI/include/QuickGUI.h"
#include "guimenu.h"

#define OIS_DYNAMIC_LIB
#include <OIS/OIS.h>

using namespace Ogre;
using namespace ml278;

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#include <CoreFoundation/CoreFoundation.h>

// This function will locate the path to our application on OS X,
// unlike windows you can not rely on the curent working directory
// for locating your configuration files and resources.
std::string macBundlePath()
{
    char path[1024];
    CFBundleRef mainBundle = CFBundleGetMainBundle();
    assert(mainBundle);

    CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
    assert(mainBundleURL);

    CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle);
    assert(cfStringRef);

    CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);

    CFRelease(mainBundleURL);
    CFRelease(cfStringRef);

    return std::string(path);
}
#endif

/** 
 * Main class tying everything together.
 * Handles input and updating of physics and graphics, and cleanup upon exit.
*/
class Application : public EventListener, public WindowEventListener, public OIS::MouseListener, public OIS::KeyListener, public OIS::JoyStickListener
{
protected:
	Ogre::Root		*mRoot;         /**< Ogre's root object */
	ExtendedCamera 	*mExCamera;	/**< Camera used */
	SceneManager	*mSceneMgr;     /**< Ogre's scenemanager object */
	RenderWindow	*mWindow;       /**< Ogre's render window */

	Ogre::String	mResourcePath;  /**< path to resources */

	bool mStatsOn;                  /**< state of the statistics overlay, true is on/displayed */
	bool mKeysOn;                   /**< state of the key-bindings overlay, true is on/displayed */ 

	// Enables/disables input
	bool mKeyboardInputEnabled;     /**< state of the keyboard input, true is on */
	bool mMouseInputEnabled;        /**< state of the mouse input, true is on */
	bool mJoystickInputEnabled;     /**< state of the joystick input, true is on */

	bool mBufferedKeys;             /**< true if the keyboard input device is buffered */
	bool mBufferedMouse;            /**< true if the mouse input device is buffered */
	bool mBufferedJoy;              /**< true if the joystick input device is buffered */
	
	int mCameraMode;
	float mManualCameraRotateSpeed;

	std::string mDebugText;         /**< string used to output debug info when necessary */
	bool mDisplayCameraDetails;		/**< true if we are to show the camera details */

        // Camera-related
        //unsigned int mCameraMode;

	unsigned int mNumScreenShots;   /**< number of screenshots taken */
	bool mContinue;        		/**< Whether to continue rendering or not*/
	TextureFilterOptions mFiltering;/**< current type of texture filtering */
	int mAniso;                     /**< current anisotropy-value used for texture filtering */

	int mSceneDetailIndex ;         /**< current scene drawing mode, 0 is solid, 1 is wireframe, 2 is points */ 
	Overlay* mDebugOverlay;         /**< the default overlay (contains FPS etc.) */
	
	// Event manager
	EventManager *mEventMgr;	/**< Manager of all event-listeners used, must be initialised to use EventListener and related methods */

	// Loadingbar
	LoadingBar *mLoadingBar;        /**< loading bar shown before the scene */
	
	//TextRender Overlay
	Ogre::OverlayManager*   mOverlayMgr;    /**< Ogre's overlaymanager */
	Ogre::Overlay*		mKeysOverlay;   /**< key-bindings help overlay */
	Ogre::OverlayContainer* mOverlayPanel;  /**< overlay container used for the key-bindings help overlay */

	//OIS Input devices
	OIS::InputManager* mInputManager;       /**< OIS input manager */
	OIS::Mouse*    mMouse;                  /**< mouse input device object */
	OIS::Keyboard* mKeyboard;               /**< keyboard input device object */
	OIS::JoyStick* mJoy;                    /**< joystick input device object */

	// Bullet-stuff
	btDynamicsWorld		*mDynamicsWorld;                        /**< Bullet dynamics world 
                                                                           * (contains objects) */
	btBroadphaseInterface	*mOverlappingPairCache;                 /**< Bullet broadphaseinterface 
                                                                           * for aabb-overlapping object pairs */
	btCollisionDispatcher	*mDispatcher;                           /**< Bullet collision dispatcher */
	btConstraintSolver	*mSolver;                               /**< Bullet constraint solver */
	btDefaultCollisionConfiguration *mCollisionConfiguration;       /**< Bullet collision configuration */

	ColShapeManager		*mColShapeMgr;                          /**< collision shape manager */
	
	KeyBindingsManager *mKeyMgr;		/**< Handles keybindings, allows to bind keys during runtime */
	GUIMenu *mGUI;				/**< In-game GUI */

        SpaceShip *mPersonalSpaceShip;

public:
	Application(bool bufferedKeys = true, bool bufferedMouse = true, bool bufferedJoy = true);
	~Application();

	void go();
        void exit();

	void windowResized(RenderWindow *rw);
	void windowClosed(RenderWindow *rw);

        void setKeyboardInput(bool);
        void setMouseInput(bool);
        void setJoystickInput(bool);

	// MouseListener
        bool mouseMoved(const OIS::MouseEvent &e);
        bool mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id);
        bool mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id);

	// KeyListener
	bool keyPressed(const OIS::KeyEvent &e);
	bool keyReleased(const OIS::KeyEvent &e);
	
	// Joystick listener
	bool povMoved( const OIS::JoyStickEvent &e, int pov );
	bool axisMoved( const OIS::JoyStickEvent &e, int axis );
	bool sliderMoved( const OIS::JoyStickEvent &e, int sliderID );
	bool buttonPressed( const OIS::JoyStickEvent &e, int button );
	bool buttonReleased( const OIS::JoyStickEvent &e, int button );

	void showDebugOverlay(bool show);
	void showKeysOverlay(bool show);
	
	bool frameStarted(const FrameEvent &evt);
	bool frameEnded(const FrameEvent &evt);

	bool initPhysics();
	void exitPhysics();

	//RenderText Overlay
	void addTextBox(
		const std::string& ID,
		const std::string& text,
		Ogre::Real x, Ogre::Real y,
		Ogre::Real width, Ogre::Real height,
		const Ogre::ColourValue& color = Ogre::ColourValue(1.0, 1.0, 1.0, 1.0));

        void removeTextBox(const std::string& ID);
        void setText(const std::string& ID, const std::string& Text);	

	void setTextureFiltering(Ogre::TextureFilterOptions);
	void setPolygonMode(int);
	void setCameraMode(int);

	bool getKeysOverlay();
	bool getStatsOverlay();
	Ogre::TextureFilterOptions getTextureFiltering();
	int getPolygonMode();
	int getCameraMode();
	Real cameraZoom;
	Real cameraZoomMin;
	Real cameraZoomMax;
protected:

	bool setup();
	bool configure();
	void chooseSceneManager();
	void createCamera();
	bool createEventHandler();
	void createScene();
        void createGUI();
	void destroyScene();
	void createViewports();
	bool setupResources();
	void createResourceListener();
	void loadResources();

	void updateStats();

	void createOverlayKeys();
};


#endif

